home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK2.toast / Development Kits (Disc 2) / QuickTime / Programming Stuff / QuickTime 2.1 for Developers / Sprite Sample Code / MakeSpriteMovie.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-19  |  17.3 KB  |  535 lines  |  [TEXT/MMCC]

  1. /*
  2.     MakeSpriteMovie.c
  3.  
  4.     This sample code shows how to create a QuickTime Sprite Track
  5.     The example creates a 640 x 480 movie with one sprite track. The
  6.     sprite track contains a static background picture sprite, or just
  7.     a color background depending on the boolean passed into AddSpriteTrackToMovie, 
  8.     and three other sprites which change their properties over time.
  9.     The track's media contains only one key frame sample followed by 
  10.     many override samples. The key frame contains all of the images
  11.     used by the sprites, the override frames only contain the
  12.     overrides of the locations, image indecies, and layers needed for the other
  13.     sprites. 
  14.     
  15.     Since each override frame is small the performance of the movie
  16.     can be improved by flattening it. (save as self contained from
  17.     Movie Player).
  18.     
  19.     This sample code also shows how any PICT can be recompressed with the
  20.     animation compressor using a key color to obtain transparency.
  21. */
  22. #include <Fonts.h>
  23. #include <Movies.h>
  24. #include <MediaHandlers.h>
  25.  
  26. // exception handling macros
  27.  
  28. #define        FailIf(a, e)         {if (a)     { err = e; goto bail; }}
  29. #define        FailOSErr(a)         {if (err = a)     goto bail;}
  30. #define        FailMemErr(a)        {a; if (err = MemError()) goto bail;}
  31.  
  32. // create a sprite movie
  33. OSErr CreateSampleSpriteMovie( void );
  34. // create a sprite track and add it to a QuickTime movie
  35. OSErr AddSpriteTrackToMovie( Movie theMovie, short trackWidth, short trackHeight, Boolean withBackgroundPicture );
  36. // set sprite properties for non-nil parameters, overriding or adding atoms as neccessary
  37. OSErr SetSpriteData( QTAtomContainer sprite, Point *location, short *visible, short *layer, short *imageIndex );
  38. // add a sprite to a sample
  39. OSErr AddSpriteToSample( QTAtomContainer theSample, QTAtomContainer theSprite, short spriteID );
  40. // add a sprite key frame sample to sprite track's media
  41. OSErr AddSpriteSampleToMedia( Media theMedia, QTAtomContainer sample, TimeValue duration, Boolean isKeyFrame );
  42. // compress a PICT with animation compressor and add image data to a sprite key sample's images container atom
  43. OSErr AddPICTImageToKeyFrameSample( QTAtomContainer keySample, short pictID, RGBColor *keyColor, short id );
  44. // add compressed image data to a sprite key sample's images container atom
  45. OSErr AddCompressedImageToKeyFrameSample( QTAtomContainer keySample, ImageDescriptionHandle idh, long dataSize, Ptr compressedDataPtr, QTAtomID imageID );
  46.  
  47. // extract the data from a PICT which contains compressed image data
  48. OSErr ExtractCompressData( PicHandle thePict, Handle *dataOut, ImageDescriptionHandle *idh );
  49. // helper routine for ExtractCompressData
  50. pascal void extractStdPix( PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode, RgnHandle mask, PixMap *matte, Rect *matteRect, short flags );
  51. // recompress PICT using animation compressor with the given key color
  52. void MakePictTransparent( PicHandle pic, RGBColor *keyColor );
  53.  
  54. typedef struct {
  55.     CGrafPort tempPort;
  56.  
  57.     Handle data;
  58.     ImageDescriptionHandle idh;
  59. } extractPictRecord;
  60.  
  61. #define compressDepth    16
  62. #define compressType    'rle '
  63.  
  64.  
  65. #define        kSpriteTrackWidth            640
  66. #define     kSpriteTrackHeight            480
  67.  
  68. #define        kIconPictID                    127
  69. #define        kWorldPictID                128
  70. #define        kBackgroundPictID            158
  71. #define        kFirstSpaceShipPictID        (kBackgroundPictID + 1)
  72.  
  73. #define        kIconImageIndex                1
  74. #define        kWorldImageIndex            2
  75. #define        kBackgroundImageIndex        3
  76. #define        kFirstSpaceShipImageIndex    4
  77. #define        kNumSpaceShipImages            24
  78. #define        kLastSpaceShipImageIndex    (kFirstSpaceShipImageIndex + kNumSpaceShipImages - 1)
  79.  
  80. #define        kSpriteMediaTimeScale        600
  81. #define        kSpriteMediaFrameDuration    8
  82. #define        kSpriteMediaFramesPerSecond    (kSpriteMediaTimeScale / kSpriteMediaFrameDuration)
  83.  
  84. #define        kNumOverrideSamples            199
  85.  
  86. void main(void)
  87. {
  88.     InitGraf( &qd.thePort );
  89.     InitFonts();
  90.     InitWindows();
  91.     InitMenus();
  92.     TEInit();
  93.     InitDialogs(0L);
  94.     InitCursor();
  95.     MaxApplZone();
  96.  
  97.     EnterMovies();
  98.  
  99.     CreateSampleSpriteMovie();
  100.     
  101.     ExitMovies();
  102. }
  103.  
  104. OSErr CreateSampleSpriteMovie( void )
  105. {
  106.     OSErr             err = noErr;
  107.     SFReply            theSFReply;
  108.     FSSpec             mySpec;
  109.     short             resRefNum = 0;
  110.     short             resId = 0;
  111.     Movie            theMovie = nil;
  112.     Point             where = {100,100};
  113.     
  114.     SFPutFile ( where, "\pEnter movie file name:", "\pMovie File", nil, &theSFReply );
  115.     FailIf ( (! theSFReply.good ), noErr );  
  116.  
  117.     FSMakeFSSpec( theSFReply.vRefNum, 0, theSFReply.fName, &mySpec );
  118.     FailOSErr( CreateMovieFile ( &mySpec, 'TVOD', smCurrentScript, createMovieFileDeleteCurFile, &resRefNum, &theMovie ) );
  119.  
  120.     FailOSErr( AddSpriteTrackToMovie( theMovie, kSpriteTrackWidth, kSpriteTrackHeight, true ) );
  121.     
  122.     FailOSErr( AddMovieResource( theMovie, resRefNum, &resId, theSFReply.fName ) );
  123. bail:
  124.     if ( resRefNum )     CloseMovieFile ( resRefNum );
  125.     if ( theMovie )        DisposeMovie ( theMovie );
  126.     return err;
  127. }
  128.  
  129. OSErr AddSpriteTrackToMovie( Movie theMovie, short trackWidth, short trackHeight, Boolean withBackgroundPicture )
  130. {
  131.     OSErr                     err = noErr;
  132.     QTAtomContainer            sample = nil;
  133.     Track                     newTrack;
  134.     Media                     newMedia;
  135.     QTAtomContainer            spriteData;
  136.     RGBColor                keyColor;
  137.     Point                    location, iconLocation;
  138.     short                    visible, layer, imageIndex, id, i, iconDelta, iconMinH, iconMaxH;
  139.  
  140.     keyColor.red = keyColor.green = keyColor.blue = 0xFFFF;        // white
  141.  
  142.     // create an empty key frame sample
  143.     FailOSErr( QTNewAtomContainer( &sample ) );
  144.  
  145.     // add images to the key frame sample
  146.     err = AddPICTImageToKeyFrameSample( sample, kIconPictID, &keyColor, 1 );
  147.     err = AddPICTImageToKeyFrameSample( sample, kWorldPictID, &keyColor, 2 );
  148.     err = AddPICTImageToKeyFrameSample( sample, kBackgroundPictID, &keyColor, 3 );
  149.     for ( i = 1; i <= kNumSpaceShipImages; i++ )
  150.         err = AddPICTImageToKeyFrameSample( sample, kFirstSpaceShipPictID + i - 1, &keyColor, i + 3 );
  151.  
  152.     // create the track, add it to theMovie, and then add samples to tracks media
  153.     newTrack = NewMovieTrack( theMovie, ((long)trackWidth << 16), ((long)trackHeight << 16), 0 );
  154.     newMedia = NewTrackMedia( newTrack, SpriteMediaType, kSpriteMediaTimeScale, nil, 0 );
  155.     
  156.     FailOSErr( BeginMediaEdits( newMedia ) );
  157.  
  158.     // add sprites to the key frame
  159.     FailOSErr( QTNewAtomContainer( &spriteData ) );
  160.  
  161.     if ( withBackgroundPicture ) {
  162.         // background
  163.         location.h     = 0;
  164.         location.v     = 0;
  165.         visible     = true;
  166.         layer        = kBackgroundSpriteLayerNum;            // this makes the sprite a background sprite
  167.         imageIndex    = kBackgroundImageIndex;
  168.         SetSpriteData( spriteData, &location, &visible, &layer, &imageIndex );
  169.         err = AddSpriteToSample( sample, spriteData, 1 );
  170.     }
  171.     
  172.     // space ship sprite
  173.     location.h     = 0;
  174.     location.v     = 60;
  175.     visible     = true;
  176.     layer        = -1;
  177.     imageIndex    = kFirstSpaceShipImageIndex;
  178.     SetSpriteData( spriteData, &location, &visible, &layer, &imageIndex );
  179.     err = AddSpriteToSample( sample, spriteData, 2 );
  180.  
  181.     // world sprite
  182.     location.h     = trackWidth / 2 - 24;
  183.     location.v     = trackHeight / 2 - 24;
  184.     visible     = true;
  185.     layer        = 1;
  186.     imageIndex    = kWorldImageIndex;
  187.     SetSpriteData( spriteData, &location, &visible, &layer, &imageIndex );
  188.     err = AddSpriteToSample( sample, spriteData, 3 );
  189.  
  190.     // icon sprite
  191.     iconDelta = 2;
  192.     iconMinH = trackWidth / 2 - 116;
  193.     iconMaxH = iconMinH + 200;
  194.     iconLocation.h     = iconMinH;
  195.     iconLocation.v     = trackHeight / 2 - 24 + 12;
  196.     layer            = 0;
  197.     imageIndex        = kIconImageIndex;
  198.     SetSpriteData( spriteData, &iconLocation, &visible, &layer, &imageIndex );
  199.     err = AddSpriteToSample( sample, spriteData, 4 );
  200.  
  201.     err = AddSpriteSampleToMedia( newMedia, sample, kSpriteMediaFrameDuration, true );    
  202.  
  203.     // now add a bunch of override frames to the media which make the space ship spin and move
  204.     imageIndex = kFirstSpaceShipImageIndex;
  205.     location.h = 0;
  206.     location.v = 80;
  207.     for ( i = 1; i < kNumOverrideSamples; i++ ) {
  208.         QTRemoveChildren( sample, 0 );
  209.         QTRemoveChildren( spriteData, 0 );
  210.         
  211.         // bump the image index every third frame to spin 
  212.         if ( (i % 3) == 0 ) {
  213.             imageIndex++;
  214.             if ( imageIndex > kLastSpaceShipImageIndex )
  215.                 imageIndex = kFirstSpaceShipImageIndex;
  216.         }
  217.         
  218.         // bump the location by one pixel vertically and two horizontally every frame to make it move
  219.         location.h += 2;
  220.         location.v++;
  221.         
  222.         SetSpriteData( spriteData, &location, nil, nil, &imageIndex );
  223.         err = AddSpriteToSample( sample, spriteData, 2 );
  224.  
  225.         // make the icon move and change layer
  226.         QTRemoveChildren( spriteData, 0 );
  227.         iconLocation.h += iconDelta;
  228.         if ( iconLocation.h >= iconMaxH ) {
  229.             iconLocation.h = iconMaxH;
  230.             iconDelta = - iconDelta;
  231.         }
  232.         if ( iconLocation.h <= iconMinH ) {
  233.             iconLocation.h = iconMinH;
  234.             iconDelta = - iconDelta;
  235.         }
  236.         if ( iconDelta > 0 )
  237.             layer = 0;
  238.         else
  239.             layer = 3;
  240.         
  241.         SetSpriteData( spriteData, &iconLocation, nil, &layer, nil );
  242.         err = AddSpriteToSample( sample, spriteData, 4 );
  243.  
  244.         err = AddSpriteSampleToMedia( newMedia, sample, kSpriteMediaFrameDuration, false );            
  245.     }
  246.         
  247.     EndMediaEdits( newMedia );
  248.     InsertMediaIntoTrack( newTrack, 0, 0, GetMediaDuration( newMedia ), 0x010000 );
  249.     
  250.     // add a background color to the sprite track
  251.     if ( withBackgroundPicture == false ) {
  252.         QTAtomContainer        trackProperties;
  253.         RGBColor            backgroundColor;
  254.         
  255.         backgroundColor.red = 0x8000;
  256.         backgroundColor.green = 0;
  257.         backgroundColor.blue = 0xffff;
  258.         
  259.         QTNewAtomContainer( &trackProperties );
  260.         QTInsertChild( trackProperties, 0, kSpriteTrackPropertyBackgroundColor, 1, 1, sizeof(RGBColor), &backgroundColor, nil );
  261.     
  262.         err = SetMediaPropertyAtom( newMedia, trackProperties );
  263.  
  264.         QTDisposeAtomContainer( trackProperties );
  265.     }
  266.     
  267. bail:
  268.     if ( sample )            QTDisposeAtomContainer( sample );
  269.     if ( spriteData )        QTDisposeAtomContainer( spriteData );
  270.  
  271.     return err;
  272. }
  273.  
  274. OSErr SetSpriteData( QTAtomContainer sprite, Point *location, short *visible, short *layer, short *imageIndex )
  275. {
  276.     OSErr    err = noErr;
  277.     QTAtom    propertyAtom;
  278.     
  279.     if ( location ) {
  280.         MatrixRecord    matrix;
  281.         
  282.         SetIdentityMatrix( &matrix );
  283.         matrix.matrix[2][0] = ((long)location->h << 16);
  284.         matrix.matrix[2][1] = ((long)location->v << 16);
  285.         
  286.         if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyMatrix, 1, nil )) == 0 )
  287.             FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyMatrix, 1, 0, sizeof(MatrixRecord), &matrix, nil ) )
  288.         else
  289.             FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(MatrixRecord), &matrix ) );
  290.     }
  291.     if ( visible ) {
  292.         if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyVisible, 1, nil )) == 0 )
  293.             FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyVisible, 1, 0, sizeof(short), visible, nil ) )
  294.         else
  295.             FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), visible ) );
  296.     }
  297.     if ( layer ) {
  298.         if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyLayer, 1, nil )) == 0 )
  299.             FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyLayer, 1, 0, sizeof(short), layer, nil ) )
  300.         else
  301.             FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), layer ) );
  302.     }
  303.     if ( imageIndex ) {
  304.         if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyImageIndex, 1, nil )) == 0 )
  305.             FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyImageIndex, 1, 0, sizeof(short), imageIndex, nil ) )
  306.         else
  307.             FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), imageIndex ) );
  308.     }
  309.     
  310. bail:
  311.     if ( err && sprite )
  312.         QTRemoveChildren( sprite, 0 );
  313.  
  314.     return err;
  315. }
  316.  
  317. OSErr AddSpriteToSample( QTAtomContainer theSample, QTAtomContainer theSprite, short spriteID )
  318. {
  319.     OSErr    err = noErr;
  320.     QTAtom    newSpriteAtom;
  321.     
  322.     FailIf ( QTFindChildByID( theSample, 0, kSpriteAtomType, spriteID, nil ), paramErr );
  323.     
  324.     FailOSErr( QTInsertChild( theSample, 0, kSpriteAtomType, spriteID, 0, 0, nil, &newSpriteAtom ) );        // index of zero means append
  325.     FailOSErr( QTInsertChildren( theSample, newSpriteAtom, theSprite ) );
  326. bail:
  327.     return err;
  328. }
  329.  
  330. OSErr AddSpriteSampleToMedia( Media theMedia, QTAtomContainer sample, TimeValue duration, Boolean isKeyFrame )
  331. {
  332.     OSErr                    err = noErr;
  333.     SampleDescriptionHandle sampleDesc = nil;
  334.     
  335.     FailMemErr( sampleDesc = (SampleDescriptionHandle) NewHandleClear( sizeof(SampleDescription ) ) );
  336.     
  337.     FailOSErr( AddMediaSample(     theMedia, (Handle) sample, 0, GetHandleSize( sample ),
  338.                                 duration, sampleDesc, 1,
  339.                                 isKeyFrame ? 0 : mediaSampleNotSync, nil ) );
  340. bail:
  341.     if ( sampleDesc )    DisposeHandle( (Handle) sampleDesc );
  342.     return err;
  343. }
  344.  
  345. OSErr AddPICTImageToKeyFrameSample( QTAtomContainer keySample, short pictID, RGBColor *keyColor, short id )
  346. {
  347.     OSErr                    err = noErr;
  348.     PicHandle                picture;
  349.     Handle                    compressedPicture;
  350.     ImageDescriptionHandle    idh;
  351.     
  352.     // get picture from resource
  353.     picture = (PicHandle) GetPicture( pictID );
  354.     DetachResource( (Handle)picture );
  355.     
  356.     // convert it to image data compressed by the animation compressor
  357.     MakePictTransparent( picture, keyColor );
  358.     ExtractCompressData( picture, &compressedPicture, &idh );
  359.  
  360.     // add it to the keySample
  361.     HLock( compressedPicture );
  362.     AddCompressedImageToKeyFrameSample( keySample, idh, GetHandleSize( compressedPicture ), *compressedPicture, id );
  363.     
  364. bail:
  365.     if ( picture )                KillPicture( picture );
  366.     if ( compressedPicture )    DisposeHandle( compressedPicture );    
  367.     if ( idh )                    DisposeHandle( (Handle)idh );    
  368.     return err;
  369. }
  370.  
  371. OSErr AddCompressedImageToKeyFrameSample( QTAtomContainer keySample, ImageDescriptionHandle idh, long dataSize, Ptr compressedDataPtr, QTAtomID imageID )
  372. {
  373.     OSErr        err = noErr;
  374.     Handle        imageData;
  375.     QTAtom        defaultsAtom, imagesContainerAtom, imageAtom;
  376.     
  377.     // append compressed picture data to imageDescription to obtain sprite image data
  378.     FailMemErr( imageData = NewHandle(0) );
  379.     FailMemErr( HandAndHand( (Handle)idh, imageData ) );
  380.     FailMemErr( PtrAndHand( compressedDataPtr, imageData, dataSize ) );
  381.     
  382.     if ( (defaultsAtom = QTFindChildByIndex( keySample, 0, kSpriteSharedDataAtomType, 1, nil )) == 0 )
  383.         FailOSErr( QTInsertChild( keySample, 0, kSpriteSharedDataAtomType, 1, 0, 0, nil, &defaultsAtom ) );
  384.         
  385.     if ( (imagesContainerAtom = QTFindChildByIndex( keySample, defaultsAtom, kSpriteImagesContainerAtomType, 1, nil )) == 0 )
  386.         FailOSErr( QTInsertChild( keySample, defaultsAtom, kSpriteImagesContainerAtomType, 1, 0, 0, nil, &imagesContainerAtom ) );
  387.  
  388.     FailOSErr( QTInsertChild( keySample, imagesContainerAtom, kSpriteImageAtomType, imageID, 0, 0, nil, &imageAtom ) );
  389.  
  390.     HLock( imageData );
  391.     FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageDataAtomType, 1, 0, GetHandleSize(imageData), *imageData, nil ) );
  392.     
  393. bail:
  394.     if ( imageData )    DisposeHandle( imageData );    
  395.     return err;
  396. }
  397.  
  398.  
  399. // PICT to compressed image conversion
  400.  
  401. OSErr ExtractCompressData( PicHandle thePict, Handle *dataOut, ImageDescriptionHandle *idh )
  402. {
  403.     OSErr                err = noErr;
  404.     extractPictRecord     state;
  405.     CQDProcs             procs;
  406.     GrafPtr             savePort;
  407.     Rect                 bounds;
  408.  
  409.     if ( dataOut )
  410.         *dataOut = nil;
  411.     if ( idh )
  412.         *idh = nil;
  413.  
  414.     GetPort( &savePort );
  415.  
  416.     OpenCPort( &state.tempPort );
  417.     SetStdCProcs( &procs );
  418.     procs.newProc1 = (UniversalProcPtr)extractStdPix;
  419.     state.tempPort.grafProcs = &procs;
  420.  
  421.     state.data = nil;
  422.     state.idh = nil;
  423.  
  424.     SetPort( (GrafPtr)&state.tempPort );
  425.     HidePen();
  426.  
  427.     bounds = (**thePict).picFrame;
  428.     DrawPicture(thePict, &bounds);    
  429.  
  430. bail:
  431.     SetPort( savePort );
  432.     CloseCPort( &state.tempPort );
  433.  
  434.     *dataOut    = state.data;
  435.     *idh        = state.idh;
  436.  
  437.     return err;
  438. }
  439.  
  440. pascal void extractStdPix( PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode, RgnHandle mask, PixMap *matte, Rect *matteRect, short flags )
  441. {
  442. #pragma unused(srcRect,matrix,mode,mask,matte,matteRect,flags)
  443.     extractPictRecord    *state;
  444.  
  445.     GetPort( (GrafPtr *)&state );
  446.  
  447.     if  ( state->idh == nil ) {
  448.         ImageDescriptionHandle    desc;
  449.         Ptr                     data;
  450.         long                    bufferSize;
  451.  
  452.         if ( GetCompressedPixMapInfo(src, &desc, &data, &bufferSize, nil, nil) == noErr ) {
  453.             state->idh = desc;
  454.             HandToHand( (Handle *)&state->idh );
  455.             PtrToHand( data, &state->data, bufferSize );
  456.         }
  457.     }
  458. }
  459.  
  460. void MakePictTransparent( PicHandle pic, RGBColor *keyColor )
  461. {
  462.     OSErr                    err;
  463.     CGrafPtr                 savePort;
  464.     GDHandle                 saveGD;
  465.     GWorldPtr                 gw = nil;
  466.     Rect                     bounds;
  467.     ImageSequence             seq = 0;
  468.     ImageDescriptionHandle     desc = nil;
  469.     Ptr                     data = 0;
  470.     long                     dataSize;
  471.     UInt8                     similarity;
  472.     PicHandle                 newPict = nil;
  473.     RGBColor                 saveBackColor;
  474.     
  475.     GetGWorld( &savePort, &saveGD );
  476.  
  477.     bounds = (**(PicHandle)pic).picFrame;
  478.     OffsetRect( &bounds, -bounds.left, -bounds.top );
  479.  
  480.     err = NewGWorld( &gw, compressDepth, &bounds, nil, nil, useTempMem );
  481.     if (err)
  482.         err = NewGWorld( &gw, compressDepth, &bounds, nil, nil, 0 );
  483.  
  484.     LockPixels( gw->portPixMap );
  485.     SetGWorld( gw, nil );
  486.  
  487.     GetBackColor( &saveBackColor );
  488.     RGBBackColor( keyColor );
  489.  
  490.         EraseRect( &bounds );
  491.  
  492.     RGBBackColor( &saveBackColor );
  493.  
  494.     desc = (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
  495.     if ( err = MemError() ) goto bail;
  496.  
  497.     err = CompressSequenceBegin( &seq, gw->portPixMap, nil, &bounds, nil, compressDepth, compressType, 0, codecMaxQuality, codecMaxQuality, 0, nil, 0, desc );
  498.     if (err) goto bail;
  499.  
  500.     err = GetMaxCompressionSize( gw->portPixMap, &bounds, compressDepth, codecMaxQuality, compressType, 0, &dataSize );
  501.     if ( err ) goto bail;
  502.  
  503.     data = NewPtr( dataSize );
  504.     if ( err = MemError() ) goto bail;
  505.  
  506.     err = CompressSequenceFrame( seq, gw->portPixMap, &bounds, codecFlagUpdatePrevious, data, &dataSize, &similarity, nil );
  507.     if ( err ) goto bail;
  508.  
  509.     DrawPicture( pic, &bounds );
  510.  
  511.     err = CompressSequenceFrame( seq, gw->portPixMap, &bounds, codecFlagUpdatePrevious, data, &dataSize, &similarity, nil );
  512.     if ( err ) goto bail;
  513.  
  514.     CDSequenceEnd( seq );
  515.     seq = 0;
  516.  
  517.     newPict =  OpenPicture( &bounds );
  518.     err = DecompressImage( data, desc, gw->portPixMap, &bounds, &bounds, ditherCopy, nil );
  519.     ClosePicture();
  520.     if ( err ) goto bail;
  521.  
  522.     SetHandleSize( (Handle)pic, 0 );
  523.     HandAndHand( (Handle)newPict, (Handle)pic );
  524.  
  525. bail:
  526.     CDSequenceEnd( seq );
  527.     SetGWorld( savePort, saveGD );
  528.     if ( gw ) DisposeGWorld( gw );
  529.     DisposeHandle( (Handle)desc );
  530.     if ( data ) DisposePtr( data );
  531.     KillPicture( newPict );
  532.  
  533.     return;
  534. }
  535.